//
//  MRMessageCenter.m
//  McRemoteServer
//
//  Created by Magic on 1/8/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "MRMessageCenter.h"
#import "FileManager.h"
#import "DockManager.h"
#import "MRAlertView.h"

#define kMessageTypeTag                 1000
#define kMessageBinarySizeTag           1001
#define kMessageBinaryBodyTag           1002
#define kMessageMacOSVersionTag         1003
#define kMessageClientInfoTag           1006



@interface MRMessageCenter () 

- (void)readNextMessage;

- (UInt32)getUInt32FromData:(NSData *)data;

- (void)handleMessageOfType:(MRMessageType)type;

- (void)onBinaryData:(NSData *)data;

- (void)onMacOSVersion:(NSData *)data;

@end


@implementation MRMessageCenter

+ (MRMessageCenter *)sharedCenter
{
    static MRMessageCenter *sharedCenter;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        sharedCenter = [[MRMessageCenter alloc] init];
    });
    
    return sharedCenter;
}

- (id)init {
    self = [super init];
    if (self) {
        
    }
    return self;
}


#pragma mark -- Private Methods --


- (void)readNextMessage
{
    [[MRClient sharedClient] readDataToLength:kMessageTypeLength tag:kMessageTypeTag timeout:-1];
}

- (UInt32)getUInt32FromData:(NSData *)data
{
    UInt32 uint32;
    [data getBytes:&uint32 length:sizeof(UInt32)];
    return uint32;
}

- (void)sendBinaryData:(NSData *)data type:(MRBinaryType)type
{
    UInt32 header[3];
    
    header[0] = kTypeBinaryData ;
    header[1] = (UInt32)[data length] + sizeof(UInt32); //warning
    header[2] = type;
  
    NSMutableData *concatenatedData = [[NSMutableData alloc] init];
    [concatenatedData appendBytes:header length:sizeof(UInt32)*3];
    [concatenatedData appendData:data];
    
    [[MRClient sharedClient] writeData:concatenatedData tag:1];
    
}

- (void)sendClientInfoMessageToServer
{
    NSString *deviceName = [[UIDevice currentDevice] name];
    NSData *data = [deviceName dataUsingEncoding:NSUTF8StringEncoding];
    //[[MRClient sharedClient] writeData:data tag:kMessageClientInfoTag];
    
    [self sendBinaryData:data type:kTypeClientDeviceName];
}

- (void)sendLaunchAppNamed:(NSString *)name
{
    NSData *data = [name dataUsingEncoding:NSUTF8StringEncoding];
    [self sendBinaryData:data type:kTypeLaunchApp];
}

- (void)onMacOSVersion:(NSData *)data
{
    UInt32 versionMajorAndMinor[2];
    [data getBytes:versionMajorAndMinor length:kMessageMacOSVersionLength];
    
    NSLog(@"Mac OS X,%lu.%lu",versionMajorAndMinor[0],versionMajorAndMinor[1]);
        
    
}

- (void)sendNeedDockIconWithName:(NSString *)name
{
    NSData *data = [name dataUsingEncoding:NSUTF8StringEncoding];
    
    [self sendBinaryData:data type:kTypeDockAppName];
}

- (void)sendIsRetina
{
    UInt32 isRetina = 0;
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] == YES && [[UIScreen mainScreen] scale] == 2.00) {
        
        NSLog(@"Retina");
        isRetina = 1;
    }
    

    UInt32 buffer[2];
    
    buffer[0] = kTypeIsRetina;
    buffer[1] = isRetina;
    
    NSData *bufferData = [NSData dataWithBytes:buffer length:sizeof(UInt32)*2];
    [[MRClient sharedClient] writeData:bufferData tag:0];

}


- (void)onBinaryData:(NSData *)data
{    
    NSUInteger offset = 0;
    UInt32 dataType = [self getUInt32FromData:data];
    NSUInteger totalLength = [data length] - sizeof(UInt32);
    
    offset += sizeof(UInt32);
    //void *bytes = (void *)[data bytes]; //body data starts from ((UInt32*)bytes[1])
   // bytes += sizeof(UInt32);
    
    
       
    switch (dataType) {
        case kTypeAppIcon:
        {
            
            UInt32 length;
            [data getBytes:&length range:NSMakeRange(offset, sizeof(UInt32))];
                                                     
            offset += sizeof(UInt32);
            
            
            NSString *appName = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(offset, length)] encoding:NSUTF8StringEncoding];
            offset += length;
            NSLog(@"on dock icon:%@",appName);
            
            [data getBytes:&length range:NSMakeRange(offset, sizeof(UInt32))];
            offset += sizeof(UInt32);
            
            NSData *appIconData = [data subdataWithRange:NSMakeRange(offset, length)];
 
            
            [[DockManager sharedManager] setDockAppIconData:appIconData forName:appName];
            

            [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationIcon" object:nil];
            
            break;
        }
            
        case kTypeDockAppName:
        {
            NSString *dockAppName = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(offset, totalLength)] encoding:NSUTF8StringEncoding];
            
        
            NSLog(@"on dock name:%@",dockAppName);
            
            [[DockManager sharedManager] addDockAppWithName:dockAppName];
            
            BOOL exists = [[FileManager sharedManager] fileExists:dockAppName extension:@"png"];
            
            if (!exists) {
                [self sendNeedDockIconWithName:dockAppName];
            } 
            
            break;
        }
        case kTypeActiveApplication:
        {
            NSString *activeAppName = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(offset, totalLength)] encoding:NSUTF8StringEncoding];
            
            NSLog(@"on active app:%@",activeAppName);
            [[DockManager sharedManager] setActiveApplicationName:activeAppName];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"ActiveApplicationChange" object:nil userInfo:[NSDictionary dictionaryWithObject:activeAppName forKey:@"name"]];
            
            break;
        }
            
        case kTypeLaunchedAppName:
        {
            NSString *launchedAppName = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(offset, totalLength)] encoding:NSUTF8StringEncoding];
            
            NSLog(@"on launch app:%@",launchedAppName);
            [[DockManager sharedManager] addLaunchedAppWithName:launchedAppName];
            
            BOOL exists = [[FileManager sharedManager] fileExists:launchedAppName extension:@"png"];
            
            if (!exists) {
                [self sendNeedDockIconWithName:launchedAppName];
            } 
            
            [[NSNotificationCenter defaultCenter] postNotificationName:@"LaunchApplication" object:nil];
            break;
        }
        case kTypeTerminateAppName:
        {
            NSString *terminateAppName = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(offset, totalLength)] encoding:NSUTF8StringEncoding];
            NSLog(@"on terminate app:%@",terminateAppName);
            
            [[DockManager sharedManager] terminateAppWithName:terminateAppName];
            
            [[NSNotificationCenter defaultCenter] postNotificationName:@"TerminateApplication" object:nil];
            break;
        }
            
        default:
            NSLog(@"wrong binary type");
            break;
    }
    
    
}

- (void)handleMessageOfType:(MRMessageType)type
{
    switch (type) {
        case kTypeMacOSVersion:
            [[MRClient sharedClient] readDataToLength:kMessageMacOSVersionLength tag:kMessageMacOSVersionTag];
            
            break;
            
        case kTypeBinaryData:
            [[MRClient sharedClient] readDataToLength:kMessageBinarySizeLength tag:kMessageBinarySizeTag];
            break;
            
        default:
            NSLog(@"wrong type");
            break;
    }
}

#pragma mark -- MRServer delegate callback --

- (void)didConnectToServer
{
    [[DockManager sharedManager] clearDock];
    [self sendIsRetina];
    [self sendClientInfoMessageToServer];
    
    [self readNextMessage];
    
    [[MRAlertView sharedAlertView] showWithTitle:NSLocalizedString(@"Connected",@"")];
}

- (void)shouldTimeoutRead
{
    [self readNextMessage];
}

- (void)didReadData:(NSData *)data withTag:(long)tag
{
    UInt32 messageType;
       
    
    if (tag == kMessageTypeTag) { //type data
        
        messageType = [self getUInt32FromData:data];
        
        //
        [self handleMessageOfType:messageType];
        
    }
    else if (tag == kMessageBinarySizeTag) { //binary length data
        
        UInt32 length = [self getUInt32FromData:data];
        [[MRClient sharedClient] readDataToLength:length tag:kMessageBinaryBodyTag];
        
    }
    else { //body data
        
        if (tag == kMessageMacOSVersionTag) {
            [self onMacOSVersion:data];
        }        
        else if (tag == kMessageBinaryBodyTag)
        {
            [self onBinaryData:data];
        }
        else
        {
            NSLog(@"wrong tag");
        }
        
        [self readNextMessage];
    }
}

- (void)sendVolumeUp
{
    UInt32 buffer[1];
    
    buffer[0] = kTypeVolumeUp;
    
    NSData *bufferData = [NSData dataWithBytes:buffer length:sizeof(UInt32)];
    [[MRClient sharedClient] writeData:bufferData tag:0];    
}

- (void)sendVolumeDown
{
    UInt32 buffer[1];
    
    buffer[0] = kTypeVolumeDown;
    
    NSData *bufferData = [NSData dataWithBytes:buffer length:sizeof(UInt32)];
    [[MRClient sharedClient] writeData:bufferData tag:0];
}

- (void)sendFinderMode:(MRFinderMode)mode
{
    UInt32 buffer[2];
    
    buffer[0] = kTypeFinderMode;
    buffer[1] = mode;
    
    NSData *bufferData = [NSData dataWithBytes:buffer length:sizeof(UInt32)*2];
    [[MRClient sharedClient] writeData:bufferData tag:0];

}

- (void)sendCommandWithTitle:(NSString *)title
                       group:(NSString *)group;
{
    if ([group isEqualToString:@"General"]) {
        if ([title isEqualToString:@"Vol+"]) {
            [self sendVolumeUp];
        }
        else if ([title isEqualToString:@"Vol-"]) {
            [self sendVolumeDown];
        }
    }
    else if ([group isEqualToString:@"Finder"]) {
        if ([title isEqualToString:@"Column Mode"]) {
            [self sendFinderMode:kColumnMode];
        }
        else if ([title isEqualToString:@"List Mode"]) {
            [self sendFinderMode:kListMode];
        }
        else if ([title isEqualToString:@"Icon Mode"]) {
            [self sendFinderMode:kIconMode];
        }
        else if ([title isEqualToString:@"Coverflow Mode"]) {
            [self sendFinderMode:kCoverflowMode];
        }
    }
}

- (void)sendKeycode:(int)keycode withFlag:(int)flag annotated:(BOOL)annotated
{
    UInt32 buffer[4];
    
    buffer[0] = kTypeKeyStrokeWithFlag ;
    buffer[1] = keycode;
    buffer[2] = flag;
    buffer[3] = annotated;
    NSData *data = [NSData dataWithBytes:buffer length:sizeof(UInt32)*4];
    [[MRClient sharedClient] writeData:data tag:0];    
}

- (void)sendKeycode:(int)keycode withFlag:(int)flag
{
    UInt32 buffer[3];
    
    buffer[0] = kTypeKeyStrokeWithFlag ;
    buffer[1] = keycode;
    buffer[2] = flag;
    NSData *data = [NSData dataWithBytes:buffer length:sizeof(UInt32)*3];
    [[MRClient sharedClient] writeData:data tag:0];
    
}

- (void)sendKeycode:(int)keycode
{
    UInt32 buffer[2];
    
    buffer[0] = kTypeKeyStroke;
    buffer[1] = keycode;
    
    NSData *data = [NSData dataWithBytes:buffer length:sizeof(UInt32)*2];
    [[MRClient sharedClient] writeData:data tag:0];
}

- (void)sendMouseMoveWithOffset:(CGPoint)offset
{
    int32_t buffer[3];
    buffer[0] = kTypeMouseMove;
    buffer[1] = offset.x;
    buffer[2] = offset.y;
    
 
    
    NSData *data = [NSData dataWithBytes:buffer length:sizeof(int32_t)*3];
    [[MRClient sharedClient] writeData:data tag:0];

}

- (void)sendLeftMouseClick
{
    UInt32 buffer[1];
    buffer[0] = kTypeLeftMouseClick;
    NSData *data = [NSData dataWithBytes:buffer length:sizeof(UInt32)];
    [[MRClient sharedClient] writeData:data tag:0];
}

- (void)sendRightMouseClick
{
    UInt32 buffer[1];
    buffer[0] = kTypeRightMouseClick;
    NSData *data = [NSData dataWithBytes:buffer length:sizeof(UInt32)];
    [[MRClient sharedClient] writeData:data tag:0];
}

- (void)sendWheelScrollWithOffset:(CGPoint)offset
{
    int32_t buffer[3];
    buffer[0] = kTypeMouseWheelScroll;
    buffer[1] = offset.x;
    buffer[2] = offset.y;
    NSData *data = [NSData dataWithBytes:buffer length:sizeof(int32_t)*3];
    [[MRClient sharedClient] writeData:data tag:0];
}

- (void)sendNeedDockInfo
{
    UInt32 buffer[1];
    buffer[0] = kTypeNeedDockInfo;
    NSData *data = [NSData dataWithBytes:buffer length:sizeof(UInt32)];
    [[MRClient sharedClient] writeData:data tag:0];
}

@end
